From fa8886590c8f3b3a8e3a0f43e68993674efa2d85 Mon Sep 17 00:00:00 2001 From: "Karl O. Pinc" Date: Tue, 10 Sep 2024 19:15:04 -0500 Subject: [PATCH] Have cookiecutter generate template tests --- setup.py | 1 + src/pgwui_develop/TEMPLATE/setup.py.mak | 1 + .../tests/templates/test_templates.py.mak | 111 ++++++++++++++++++ src/pgwui_develop/testing.py | 11 ++ tests/test_testing.py | 33 +++++- 5 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/pgwui_develop/TEMPLATE/tests/templates/test_templates.py.mak diff --git a/setup.py b/setup.py index fcfce71..9668751 100644 --- a/setup.py +++ b/setup.py @@ -65,6 +65,7 @@ extras_require = { "test": [ 'pytest>=3.7.4', 'pytest-cov', + 'deepdiff', ] } diff --git a/src/pgwui_develop/TEMPLATE/setup.py.mak b/src/pgwui_develop/TEMPLATE/setup.py.mak index c131b0f..8e7ecd3 100644 --- a/src/pgwui_develop/TEMPLATE/setup.py.mak +++ b/src/pgwui_develop/TEMPLATE/setup.py.mak @@ -74,6 +74,7 @@ install_requires = [ extras_require = { "test": [ "pgwui_develop==" + version, + "pgwui_server==" + version, "WebTest >= 1.3.1", # py3 compat "pytest>=3.7.4", "pytest-cov", diff --git a/src/pgwui_develop/TEMPLATE/tests/templates/test_templates.py.mak b/src/pgwui_develop/TEMPLATE/tests/templates/test_templates.py.mak new file mode 100644 index 0000000..d0888ab --- /dev/null +++ b/src/pgwui_develop/TEMPLATE/tests/templates/test_templates.py.mak @@ -0,0 +1,111 @@ +# Copyright (C) 2024 The Meme Factory, Inc. http://www.karlpinc.com/ + +# This file is part of ${component}. +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License along with this program. If not, see +# . +# + +# Karl O. Pinc + +import mako.lookup +import mako.template +import pytest +import pgwui_core.constants +import pgwui_server.pgwui_server +import pgwui_develop.testing +import pyramid.testing + +# A dict of "standard" settings +pgwui_settings = {'dry_run': False, + '${component.lower()}': + {'menu_label': 'Test menu label'}, + } +config = pgwui_server.pgwui_server.pgwui_server_config( + {'pgwui': pgwui_settings, + 'session.secret': '1234567890123456789012345678901234567890'}) +# pgwui_upload_core.pgwui_upload_core.set_upload_response() copies the +# particular upload settings to a name ('upload_settings') used by +# pgwui_upload_core. So we need all the "upload core" settings under +# that key. But this must happen after the config is checked for +# validity since there is no 'upload_settings' component/setting. +# All this is only necessary when testing templates that inherit +# from pgwui_upload_core.templates/upload.mak, because that template +# expects these values. +config.get_settings()[ + 'pgwui']['upload_settings'] = {'null': 'choice-yes', + 'trim': 'choice-yes', + 'file_format': 'csv', + 'literal_column_headings': 'choice-yes' + } +request = pyramid.testing.DummyRequest() +request.registry = config.registry + +stock_template_args = { + 'pgwui': config.get_settings()['pgwui'], + 'havecreds': False, + 'errors': [], + 'hosts': 'localhost', + 'db': 'template1', + 'user': '', + 'csrf_token': 'somecsrftoken', + 'filename': '', + 'db_changed': '', + 'csv_value': pgwui_core.constants.CSV, + 'tab_value': pgwui_core.constants.TAB, + 'csv_checked': pgwui_core.constants.CHECKED, + 'tab_checked': pgwui_core.constants.UNCHECKED, + 'upload_null': pgwui_core.constants.CHECKED, + 'null_rep': '', + 'trim_upload': pgwui_core.constants.CHECKED, + 'literal_col_headings': pgwui_core.constants.UNCHECKED, +} + +# The templates to test +TEMPLATES = ['${short_name}.mak'] +logged_in_args = pgwui_develop.testing.update_copy( + stock_template_args, {'havecreds': True}) + +# Add the request to all the arguments. +# (The request won't deepcopy, so we don't try.) +stock_template_args['request'] = request +logged_in_args['request'] = request + +# The variables with which to test each template +TEMPLATE_ARGS = { + '${short_name}.mak': + [stock_template_args, + logged_in_args], +} + +# Transform TEMPLATE_ARGS into something pytest can use with parametrize. +parameter_args = [] +for tfile, values in iter(TEMPLATE_ARGS.items()): + for value in values: + parameter_args.append((tfile, value)) + +# All imports are through asset paths, which become fully qualified paths. +lookup_dirs = mako.lookup.TemplateLookup(directories=['/']) + + +# Template rendering tests + +@pytest.mark.parametrize('tfile,values', parameter_args) +def test_templates(tfile, values): + '''All the templates render without error + ''' + template = mako.template.Template( + filename=f'src/${component.lower()}/templates/{tfile}', + lookup=lookup_dirs) + template.render(**values) diff --git a/src/pgwui_develop/testing.py b/src/pgwui_develop/testing.py index 17f5b72..62bb6f8 100644 --- a/src/pgwui_develop/testing.py +++ b/src/pgwui_develop/testing.py @@ -21,12 +21,23 @@ # Karl O. Pinc from unittest import mock +import copy import functools import sys import warnings import pytest +# Utilities for generating test data. +def update_copy(copied, newvals): + '''Deep copy a dictionary, update the copy with Dict.update(), return + the copy. + ''' + new = copy.deepcopy(copied) + new.update(newvals) + return new + + # Utility decorator # Pyramid 2.0 added deprecation warnings to pyramid.request.Request. diff --git a/tests/test_testing.py b/tests/test_testing.py index 7680763..04d67b1 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -23,6 +23,8 @@ # See: https://pytest-cov.readthedocs.io/en/latest/plugins.html +import copy +import deepdiff import pytest import sys @@ -33,10 +35,39 @@ from pgwui_develop import testing # Test functions # -# ignore_depreciation_warnings() +# update_copy() # +def test_update_copy(): + '''Deep copies a dict, then updates the copy + ''' + test_dict = {'outer': {'inner.key': 'inner value'}, + 'outer.key': 'outer value'} + update_dict = {'updated_key': 'updated value', + 'outer.key': 'updated outer value'} + copied_dict = copy.deepcopy(test_dict) + copied_dict.update(update_dict) + + result_dict = testing.update_copy(test_dict, update_dict) + + # Shallow copy tests + assert result_dict != test_dict + assert result_dict == copied_dict + + assert deepdiff.DeepDiff( + result_dict, copied_dict, threshold_to_diff_deeper=1.0) == {} + # Deep copy tests + copy2 = copy.deepcopy(test_dict) + copy2.update({'outer': {}}) + assert result_dict != copy2 + assert deepdiff.DeepDiff( + result_dict, copy2, threshold_to_diff_deeper=1.0) != {} + + +# +# ignore_depreciation_warnings() +# @pytest.mark.parametrize( ('ignore', 'warn_cnt'), [pytest.param( -- 2.34.1